#include "NeoComboBoxStyle.h"
#include "def.h"
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>

NeoComboBoxStyle::NeoComboBoxStyle(QStyle *style)
    : QProxyStyle(style) {}

NeoComboBoxStyle::NeoComboBoxStyle(const QString &key)
    : QProxyStyle(key) {}

NeoComboBoxStyle::~NeoComboBoxStyle() = default;

void NeoComboBoxStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    switch (element)
    {
    case PE_Frame:
    case PE_Widget:
    case PE_PanelLineEdit:
    case PE_FrameFocusRect:
    case PE_PanelMenu:
    case PE_IndicatorArrowDown:
        return;
    default:
        break;
    }
    return QProxyStyle::drawPrimitive(element, option, painter, widget);
}

void NeoComboBoxStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    switch (element)
    {
    case CE_ComboBoxLabel:
        return;
    case CE_ShapedFrame:
    {
        break;
    }
    case CE_ItemViewItem:
    {
        if (const QStyleOptionViewItem *viewItemOption = qstyleoption_cast<const QStyleOptionViewItem *>(option))
        {
            const int borderRadius = 5;
            const int lineRadius = 1;
            const int indent = 20;

            painter->save();
            painter->setRenderHint(QPainter::Antialiasing);
            QRect adjustedRect = viewItemOption->rect.adjusted(NEO_RADIUS_ADJUSTED_VALUES);
            if (viewItemOption->state & QStyle::State_MouseOver ||
                viewItemOption->state & QStyle::State_Selected)
            {
                painter->setPen(Qt::lightGray);
                painter->setBrush(Qt::lightGray);
            }
            else
            {
                painter->setPen(Qt::NoPen);
                painter->setBrush(Qt::transparent);
            }
            painter->drawRoundedRect(adjustedRect, borderRadius, borderRadius);
            painter->restore();

            painter->save();
            painter->setRenderHint(QPainter::Antialiasing);
            painter->setRenderHint(QPainter::TextAntialiasing);
            painter->setPen(Qt::black);
            QRect textRect = adjustedRect.adjusted(indent, 0, 0, 0);
            painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, viewItemOption->text);
            painter->restore();

            painter->save();
            painter->setRenderHint(QPainter::Antialiasing);
            if (viewItemOption->state & QStyle::State_Selected)
            {
                painter->setPen(Qt::blue);
                painter->setBrush(Qt::blue);
            }
            else
            {
                painter->setPen(Qt::NoPen);
                painter->setBrush(Qt::NoBrush);
            }
            QRect lineRect = adjustedRect.adjusted(8 * lineRadius, 2 * lineRadius, 10 * lineRadius - adjustedRect.width(), -2 * lineRadius);
            painter->drawRoundedRect(lineRect, lineRadius, lineRadius);
            painter->restore();
            return;
        }
        break;
    }
    default:
        break;
    }
    QProxyStyle::drawControl(element, option, painter, widget);
}

void NeoComboBoxStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{
    if (const QStyleOptionComboBox *comboBoxOption = qstyleoption_cast<const QStyleOptionComboBox *>(option))
    {
        const int borderRadius = 5;
        const int lineRadius = 1;

        painter->save();
        painter->setRenderHint(QPainter::Antialiasing);
        QRect adjustedRect = comboBoxOption->rect.adjusted(NEO_RADIUS_ADJUSTED_VALUES);
        painter->setPen(Qt::lightGray);
        if (comboBoxOption->state & QStyle::State_MouseOver)
        {
            painter->setBrush(Qt::lightGray);
        }
        else
        {
            painter->setBrush(Qt::NoBrush);
        }
        painter->drawRoundedRect(adjustedRect, borderRadius, borderRadius);
        painter->restore();

        painter->save();
        painter->setRenderHint(QPainter::TextAntialiasing);
        QRect textRect = subControlRect(control, option, SC_ComboBoxEditField, widget).adjusted(NEO_RADIUS_ADJUSTED_VALUES);
        painter->setPen(Qt::black);
        painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, comboBoxOption->currentText);
        painter->restore();

        painter->save();
        painter->setRenderHint(QPainter::Antialiasing);
        painter->setRenderHint(QPainter::TextAntialiasing);
        QRect arrowRect = subControlRect(control, option, SC_ComboBoxArrow, widget).adjusted(NEO_RADIUS_ADJUSTED_VALUES);
        painter->setPen(Qt::gray);
        QFont font = QFont("Font Awesome 6 Free Solid");
        font.setPixelSize(25);
        painter->setFont(font);
        painter->drawText(arrowRect, Qt::AlignCenter, QChar((unsigned short)NeoIconType::FontAwesomeSolid::AngleDown));
        painter->restore();

        painter->save();
        painter->setRenderHint(QPainter::Antialiasing);
        painter->setRenderHint(QPainter::TextAntialiasing);
        QRect lineRect = comboBoxOption->rect.adjusted(2 * lineRadius, comboBoxOption->rect.height() - 2 * lineRadius, -2 * lineRadius, 0);
        if (comboBoxOption->state & QStyle::State_On)
        {
            painter->setPen(Qt::blue);
            painter->setBrush(Qt::blue);
        }
        else
        {
            painter->setPen(Qt::NoPen);
            painter->setBrush(Qt::NoBrush);
        }
        painter->drawRoundedRect(lineRect, lineRadius, lineRadius);
        painter->restore();
        return;
    }
    return QProxyStyle::drawComplexControl(control, option, painter, widget);
}

QRect NeoComboBoxStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const
{
    QRect comboBoxRect = QProxyStyle::subControlRect(control, option, SC_ComboBoxFrame, widget);
    switch (subControl)
    {
    case SC_ComboBoxEditField:
    {
        const int indent = 20;
        return QRect(comboBoxRect.left() + indent, comboBoxRect.top(), comboBoxRect.width() - comboBoxRect.height(), comboBoxRect.height());
    }
    case SC_ComboBoxArrow:
    {
        return QRect(comboBoxRect.right() - comboBoxRect.height(), comboBoxRect.top(), comboBoxRect.height(), comboBoxRect.height());
    }
    case SC_ComboBoxListBoxPopup:
    {
        const int gap = 5;
        return QRect(comboBoxRect.left(), comboBoxRect.bottom(), comboBoxRect.width(), gap);
    }
    default:
        break;
    }
    return QProxyStyle::subControlRect(control, option, subControl, widget);
}

QSize NeoComboBoxStyle::sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const
{
    switch (type)
    {
    case CT_ItemViewItem:
    {
        QSize size = QProxyStyle::sizeFromContents(type, option, contentsSize, widget);
        return QSize(size.width(), 30);
    }
    default:
        break;
    }
    return QProxyStyle::sizeFromContents(type, option, contentsSize, widget);
}
